/*
Copyright 2010 SGSL

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.dataiti.sgsl.globe;


import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.util.ArrayList;
import java.util.Iterator;
import com.jhlabs.globe.Globe;
import com.jhlabs.map.layer.Feature;
import com.jhlabs.map.layer.Layer;
import com.jhlabs.map.layer.SeaLayer;
import com.jhlabs.map.layer.ShapefileLayer;


/**
 * SGSLGlobe extends JHLabs Globe to provide added functionalities like printing,
 * adding label to globe
 * 
 *
 */
public class SGSLGlobe extends Globe implements Printable {
	
	private Layer map =null;	
	private String printLabel ="";
	private int[] pageBreaks;  // array of page break line positions.

	
	

	/**
	 * 
	 * Constructor will be invoked when SGSLGlob object is invoked 
	 * and the reference of map object also be stored here. 
	 *
	 */
	public SGSLGlobe()
	{			
		super();
		this.map = super.getMap();
	}
	
	
	/**
	 *  This method used to set Layer on the globe 
	 *  @param objLayer - Layer to set on the globe
	 *  
	 */
	public void setLayer(Layer objLayer)
	{
		map.addLayer(objLayer);
		super.repaint();
	}
	
	
	/**
	 * This method is to add new feature to the globe
	 * 
	 * @param objFeature - New feature to be added
	 * 
	 */
	public void setFeature(Feature objFeature)
	{	
		Iterator layers = map.getLayers().iterator();		
		
		while (layers.hasNext())
		{
			Object objlayer = layers.next();
			
			if (objlayer instanceof Layer) {
				//got map layer
				Layer tempLayer = (Layer) objlayer;
				
				Iterator seaLayers = tempLayer.getLayersIterator();
				while (seaLayers.hasNext()){
					Object objSeaLayer = seaLayers.next();
					if (objSeaLayer instanceof SeaLayer) {
						SeaLayer seaLayer = (SeaLayer)objSeaLayer;						
	                    Iterator shapeLayers = seaLayer.getLayersIterator();
						while (shapeLayers.hasNext()) {
							Object objShapeLayer = shapeLayers.next();
							if (objShapeLayer instanceof ShapefileLayer) {
								ShapefileLayer shapeLayer = (ShapefileLayer) objShapeLayer;
								shapeLayer.addFeature(objFeature);		
								break;
							}
						}
					}
					
				}
				
			}
		}
	    super.repaint();		
	}
	
	
	/**
	 * This method returns map object
	 * @return - map- Map on the globe of type Layer
	 * 
	 * 
	 */
	public Layer getMap()
	{
		return map;
	}
    
	
	/**
	 * Prints the globe along with print message  
	 * 
	 */
	public void print() {
		try {
		
			PrinterJob printJob = PrinterJob.getPrinterJob();
			printJob.setPrintable(this);
			
			if (printJob.printDialog())
			try { 
					printJob.print();
			} catch(PrinterException pe) {
				pe.printStackTrace();
			}
			
			
		}
		catch ( Exception e ) {
			e.printStackTrace();
		}
	}
    
	
	/**
	 * This method returns print label
	 * @return label - Print label of type String
	 */
	public String getPrintLabel() {
		return printLabel;
	}
   
	
	/**
	 * This method sets print label
	 * @param Label -  Print label of type String
	 */
	public void setPrintLabel(String printLable) {
		this.printLabel += printLable;
	}
	
    
	/**
	 * This method converts unformated string in to printable format
	 * @param str - Unfromatted string
	 * @return formatted String of type arrayList
	 */
	private ArrayList convertText(String str)
	{
		ArrayList list =new ArrayList();
		char[] chArray = str.toCharArray();
		
	
    	 for (int i=0;i<chArray.length;i++){
			 
    		String line = "";
			 
			for (int lc =0;((lc < 80)&&(i<chArray.length)) ;lc++)
			{   			
				char ch = chArray[i];				
				if (ch== '\n')
				{
					break;
				}
				else
				{
					line = line.concat(String.valueOf(ch));
				}
				i++;
			}
			list.add(line);
		 }
		return list;
	}
    
	
	/**
	 * This method implements print method of printable interface.
	 * @param Graphics - Graphics object which holds pritable object
	 * @param pageFormat - This holds format settings of the page.
	 * @param pageIndex - This gives the pageIndex to be printed
	 * 
	 * 
	 */
	public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
		
		ArrayList formatText = null;
		int lineHeight =0;
		int globeHeight =  this.getHeight();
		Font font =null;
		int firstPageLineCount =0;
		int pageIndexCorrection =0;

		if ((printLabel != null)) {						
			
			font = new Font("Serif", Font.ITALIC, 14);
			FontMetrics metrics = g.getFontMetrics(font);
			lineHeight = metrics.getHeight();
			
			formatText = convertText(printLabel);
			int linesPerPage = (int) ((pageFormat
					.getImageableHeight()-50) / lineHeight); // here 50 is added to avoid missing of last few lines
			
			
			if (globeHeight<pageFormat.getImageableHeight() )
			{
				firstPageLineCount = ((int)pageFormat.getImageableHeight()-globeHeight)/lineHeight;
			}
			else
			{
				pageIndexCorrection=1;
			}
			
			int newTextSize = formatText.size()-firstPageLineCount-1;					
			int numBreaks = (newTextSize) / linesPerPage;
			numBreaks++;
			pageBreaks = new int[numBreaks];
			for (int b = 0; b < numBreaks; b++) {
				if ((b==0 )&&(firstPageLineCount!=0)){
					 
					pageBreaks[b] = (b + 1) * firstPageLineCount;
					
				}
				else{
					pageBreaks[b] = (b + 1) * linesPerPage;						
				}
				if (pageBreaks[b] > formatText.size())
				{
					pageBreaks[b] = formatText.size();
				}
				
			}			
		}
		
		if ((pageIndex-pageIndexCorrection) >= pageBreaks.length) {
			return(NO_SUCH_PAGE);
		} 
		
		
		Graphics2D g2d = (Graphics2D) g;

		g2d.translate(pageFormat.getImageableX() - 50, pageFormat
				.getImageableY());
		g2d.scale(0.6f, 0.6f);
		g2d.setFont(font);
		
		
        if ((printLabel != null)&&
        	((pageIndexCorrection==0)||
        	 ((pageIndexCorrection==1)&&(pageIndex!=0)))) {

			/*
			 * Draw each line that is on this page. Increment 'y'
			 * position by lineHeight for each line.
			 */
			int y = 0;
			int start = ((pageIndex-pageIndexCorrection) == 0) ? 0
					: pageBreaks[(pageIndex-pageIndexCorrection) - 1];
			int end = ((pageIndex-pageIndexCorrection) == pageBreaks.length) ? formatText.size() : pageBreaks[(pageIndex-pageIndexCorrection)];
			
			for (int line = start; line < end; line++)
			{
				
				y += lineHeight;

				if (((pageIndex-pageIndexCorrection) == 0) &&(globeHeight<pageFormat
						.getImageableHeight())) {
					// here image will be on top portion
					g2d.drawString((String)formatText.get(line),
							100,y+globeHeight);		
				} else {
					g2d.drawString((String)formatText.get(line),
							100,y);
					
				}
			}     

		}
		
        //make sure to print image only once
		if (pageIndex==0) {					
			paint(g2d);			
		}
		
		return (PAGE_EXISTS);

	}
	
}


